/*
 * vtkFlRenderWindowInteractor - class to enable VTK to render to and interact
 * with a FLTK window.
 * 
 * Copyright (c) 2001 Charl P. Botha <cpbotha@ieee.org>
 * Based on original code and concept copyright (c) 2000,2001 David Pont
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 * 
 * See the .cxx for more notes.
 * 
 * $Id: vtkFlRenderWindowInteractor.cxx 2 2001-03-15 09:25:45Z cpbotha $
 */

/*  
 * You must not delete one of these classes.  Make use of the Delete()
 * method... this thing makes use of VTK reference counting.  Let me
 * repeat that: never "delete" an instance of this class, always use
 * ->Delete().
 */

#include "vtkFlRenderWindowInteractor.h"
// FLTK
#include <FL/x.H>
#ifndef MESA
#include <GL/gl.h>  // glDrawBuffer
#endif
// vtk
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkInteractorStyle.h>
#ifndef WIN32
#include <vtkOpenGLRenderWindow.h>
#endif
#include <vtkObjectFactory.h>


//---------------------------------------------------------------------------
vtkFlRenderWindowInteractor::vtkFlRenderWindowInteractor()
    : Fl_Window( 0, 0, 300, 300, "" ), vtkRenderWindowInteractor()
{
    // subclass of Fl_Group, call end so children cant be added
    this->end();
}
//---------------------------------------------------------------------------
vtkFlRenderWindowInteractor::vtkFlRenderWindowInteractor( int x, int y, int w, int h, const char *l )
    : Fl_Window( x, y, w, h, l ), vtkRenderWindowInteractor()
{
    // subclass of Fl_Group, call end so children cant be added
    this->end();
}
//---------------------------------------------------------------------------
vtkFlRenderWindowInteractor::~vtkFlRenderWindowInteractor()
{
   // according to the fltk docs, destroying a widget does NOT remove it from
   // its parent, so we have to do that explicitly
   if (parent())
     ((Fl_Group*)parent())->remove(*(Fl_Window*)this);
}
//---------------------------------------------------------------------------
vtkFlRenderWindowInteractor * vtkFlRenderWindowInteractor::New()
{
   // we don't make use of the objectfactory, because we're not registered
   return new vtkFlRenderWindowInteractor;
}
//---------------------------------------------------------------------------
void vtkFlRenderWindowInteractor::Initialize()
{
  // if don't have render window then stuck
  if (!RenderWindow)
  {
    vtkErrorMacro(<< "vtkFlRenderWindowInteractor::Initialize has no render window");
    return;
  }

  int *size = RenderWindow->GetSize();
  // enable everything and start rendering
  Enable();
  RenderWindow->Start();

  // set the size in the render window interactor
  Size[0] = size[0];
  Size[1] = size[1];

  // this is initialized
  Initialized = 1;
}
//---------------------------------------------------------------------------
void vtkFlRenderWindowInteractor::Enable()
{
  // if already enabled then done
  if (Enabled)
    return;

  // that's it
  Enabled = 1;
  Modified();
}
//---------------------------------------------------------------------------
void vtkFlRenderWindowInteractor::Disable()
{
  // if already disabled then done
  if (!Enabled)
    return;

  // that's it (we can't remove the event handler like it should be...)
  Enabled = 0;
  Modified();
}
//---------------------------------------------------------------------------
void vtkFlRenderWindowInteractor::Start()
{
  // the interactor cannot control the event loop
  vtkErrorMacro(<<"vtkFlRenderWindowInteractor::Start() interactor cannot control event loop.");
}
//---------------------------------------------------------------------------
void vtkFlRenderWindowInteractor::UpdateSize(int W, int H)
{
   if (RenderWindow != NULL)
   {
      // if the size changed tell render window
      if ( (W != Size[0]) || (H != Size[1]) )
      {
	 Size[0] = W;
	 Size[1] = H;
	 RenderWindow->SetSize(W, H);
	 
	 // FLTK can move widgets on resize
	 int *pos = RenderWindow->GetPosition();
	 if( pos[0] != x() || pos[1] != y() ) {
	    RenderWindow->SetPosition( x(), y() );
	 }
      }
   }
}
//---------------------------------------------------------------------------
void OnTimerGlobal(void *p)
{
   if (p)
     ((vtkFlRenderWindowInteractor *)p)->OnTimer();
}

//---------------------------------------------------------------------------
int vtkFlRenderWindowInteractor::CreateTimer(int timertype)
{
   // to be called every 10 milliseconds, one shot timer
   // we pass "this" so that the correct OnTimer instance will be called
   if (timertype=VTKI_TIMER_FIRST)
     Fl::add_timeout(0.01, OnTimerGlobal, (void *)this);
   else
     Fl::repeat_timeout(0.01, OnTimerGlobal, (void *)this);     
   
   return 1;
   // NB: if we only use add_timeout, we can overrun ourselves and a spinning
   // vtk model will keep on spinning and the application won't accept any
   // more interaction; Fl::repeat_timer() is more correct, it doesn't measure
   // the timeout from now, but from when the system call that caused this
   // timeout elapsed.

}
//---------------------------------------------------------------------------
int vtkFlRenderWindowInteractor::DestroyTimer()
{
  // do nothing
  return 1;
}

void vtkFlRenderWindowInteractor::OnTimer(void)
{
   if (!Enabled)
     return;
   InteractorStyle->OnTimer();
}


//---------------------------------------------------------------------------
void vtkFlRenderWindowInteractor::TerminateApp()
{
    ;
}

//---------------------------------------------------------------------------
// FLTK event handlers
//---------------------------------------------------------------------------
void vtkFlRenderWindowInteractor::draw(void){
   if (RenderWindow!=NULL) 
   {
      UpdateSize( this->w(), this->h() );

#ifdef WIN32
      RenderWindow->SetWindowId( fl_xid( this ) );
#else
      ((vtkXRenderWindow*)RenderWindow)->SetWindowId( fl_xid( this ) );
      RenderWindow->SetDisplayId( fl_display );
#endif
      
      Render();
   }
   else Fl_Window::draw(); // before RenderWindow created
}
//---------------------------------------------------------------------------
void vtkFlRenderWindowInteractor::resize( int x, int y, int w, int h ) {
    UpdateSize( w, h );
    Fl_Window::resize( x, y, w, h ); // resize the FLTK window
}
//---------------------------------------------------------------------------
// main FLTK event handler
int vtkFlRenderWindowInteractor::handle( int event ) {
   if( !Enabled ) return 0;

   switch( event ) 
   {
    case FL_FOCUS:
    case FL_UNFOCUS:
      ;   // Return 1 if you want keyboard events, 0 otherwise. Yes we do
      break;
      
    case FL_KEYBOARD:   // key press
      InteractorStyle->OnChar(Fl::event_state( FL_CTRL ), Fl::event_state( FL_SHIFT ), Fl::event_key(), 1);
      break;
      
    case FL_PUSH: // mouse down
      this->take_focus();  // this allows key events to work
      switch( Fl::event_button() ) 
      {
       case FL_LEFT_MOUSE:
	 InteractorStyle->OnLeftButtonDown(Fl::event_state( FL_CTRL ), Fl::event_state( FL_SHIFT ), Fl::event_x(), this->h()-Fl::event_y()-1);
	 break;
       case FL_MIDDLE_MOUSE:
	 InteractorStyle->OnMiddleButtonDown(Fl::event_state( FL_CTRL ), Fl::event_state( FL_SHIFT ), Fl::event_x(), this->h()-Fl::event_y()-1);
	 break;
       case FL_RIGHT_MOUSE:
	 InteractorStyle->OnRightButtonDown(Fl::event_state( FL_CTRL ), Fl::event_state( FL_SHIFT ), Fl::event_x(), this->h()-Fl::event_y()-1);
	 break;
      }
      break; // this break should be here, at least according to vtkXRenderWindowInteractor

    // we test for both of these, as fltk classifies mouse moves as with or
    // without button press whereas vtk wants all mouse movement
    case FL_DRAG:
    case FL_MOVE:
      InteractorStyle->OnMouseMove(Fl::event_state( FL_CTRL ), Fl::event_state( FL_SHIFT ), Fl::event_x(), this->h()-Fl::event_y()-1);
      this->redraw();
      break;

    case FL_RELEASE:    // mouse up
      switch( Fl::event_button() ) {
       case FL_LEFT_MOUSE:
	 InteractorStyle->OnLeftButtonUp(Fl::event_state( FL_CTRL ), Fl::event_state( FL_SHIFT ), Fl::event_x(), this->h()-Fl::event_y()-1);
	 break;
       case FL_MIDDLE_MOUSE:
	 InteractorStyle->OnMiddleButtonUp(Fl::event_state( FL_CTRL ), Fl::event_state( FL_SHIFT ), Fl::event_x(), this->h()-Fl::event_y()-1);
	 break;
       case FL_RIGHT_MOUSE:
	 InteractorStyle->OnRightButtonUp(Fl::event_state( FL_CTRL ), Fl::event_state( FL_SHIFT ), Fl::event_x(), this->h()-Fl::event_y()-1);
	 break;
      }
      this->redraw();
      break;

    default:	// let the base class handle everything else 
      return Fl_Window::handle( event );

   } // switch(event)...

   return 1; // we handled the event
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

